package com.sensorfriendlylearning.gcm.demo;

import java.io.IOException;
import java.util.logging.Level;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.android.gcm.server.Constants;
import com.google.android.gcm.server.Message;
import com.google.android.gcm.server.Message.Builder;
import com.google.android.gcm.server.Result;
import com.google.android.gcm.server.Sender;
import com.google.appengine.api.taskqueue.Queue;
import com.google.appengine.api.taskqueue.QueueFactory;

@SuppressWarnings("serial")
public class MessageForwardServlet extends BaseServlet {

	private static final String HEADER_QUEUE_COUNT = "X-AppEngine-TaskRetryCount";
	private static final String HEADER_QUEUE_NAME = "X-AppEngine-QueueName";
	private static final int MAX_RETRY = 3;

	private static final String PARAMETER_USER_ID = "userId";
	private static final String PARAMETER_JSON_PATH = "jsonPath";
	private static final String PARAMETER_ICON_PATH = "iconPath";
	
	private Sender sender;

	@Override
	public void init(ServletConfig config) throws ServletException {
		super.init(config);
		sender = newSender(config);
	}

	/**
	 * Creates the {@link Sender} based on the servlet settings.
	 */
	protected Sender newSender(ServletConfig config) {
		String key = (String) config.getServletContext().getAttribute(
				ApiKeyInitializer.ATTRIBUTE_ACCESS_KEY);
		return new Sender(key);
	}

	/**
	 * Indicates to App Engine that this task should be retried.
	 */
	private void retryTask(HttpServletResponse resp) {
		resp.setStatus(500);
	}

	/**
	 * Indicates to App Engine that this task is done.
	 */
	private void taskDone(HttpServletResponse resp) {
		resp.setStatus(200);
	}

	private Message createForwardMessage(String jsonPath, String iconPath) {
		Builder messageBuidler = new Message.Builder();
		messageBuidler.addData(PARAMETER_JSON_PATH, jsonPath);
		if(iconPath != null){
			messageBuidler.addData(PARAMETER_ICON_PATH, iconPath);
		}
		return messageBuidler.build();
	}

	/**
	 * Processes the request to add a new message.
	 */
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws IOException {
		
		String userId = req.getParameter(PARAMETER_USER_ID);
		String jsonPath = req.getParameter(PARAMETER_JSON_PATH);
		String iconPath = req.getParameter(PARAMETER_ICON_PATH);
		
		if (userId != null && jsonPath != null) {
			String regId = Datastore.findDeviceByUserId(userId);
			if(regId != null){
				forwardMessage(regId, jsonPath, iconPath, resp);
			}
			return;
		}
		logger.severe("Invalid request! User does not exist.");
		taskDone(resp);
		return;
	}

	private void forwardMessage(String regId, String jsonPath, String iconPath, HttpServletResponse resp) {
		logger.info("Sending message to device " + regId);
		Message message = createForwardMessage(jsonPath, iconPath);
		Result result;
		try {
			logger.severe("sending to " + regId);
			result = sender.sendNoRetry(message, regId);
		} catch (IOException e) {
			logger.log(Level.SEVERE, "Exception posting " + message, e);
			taskDone(resp);
			return;
		}
		if (result == null) {
			retryTask(resp);
			return;
		}
		if (result.getMessageId() != null) {
			logger.info("Succesfully sent message to device " + regId);
			String canonicalRegId = result.getCanonicalRegistrationId();
			if (canonicalRegId != null) {
				// same device has more than on registration id: update it
				logger.finest("canonicalRegId " + canonicalRegId);
				Datastore.updateRegistration(regId, canonicalRegId);
			}
		} else {
			String error = result.getErrorCodeName();
			if (error.equals(Constants.ERROR_NOT_REGISTERED)) {
				// application has been removed from device - unregister it
				Datastore.unregister(regId);
			} else {
				logger.severe("Error sending message to device " + regId + ": "
						+ error);
			}
		}
	}

}
